package com.epoch.base.export;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.PropertyUtils;
import org.slf4j.Logger;

import com.epoch.base.util.LoggerUtil;
import com.jfinal.plugin.activerecord.Model;
import com.jfinal.plugin.activerecord.Record;

public abstract class AbstractExporter implements IFileExporter {
    private static final Logger LOGGER = LoggerUtil.getLogger();

    @Override
    public File export(Collection<?> data, String folderPath, List<HeadMeta> headMetas,
        Map<Integer, IExportConvertor> indexCvtorMap, Map<String, IExportConvertor> fieldCvtorMap,
        Map<String, Object> params) throws ExportException {
        File file = this.genFile(folderPath);
        BufferedOutputStream out = null;
        try {
            out = new BufferedOutputStream(new FileOutputStream(file));
            this.doExport(out, data, headMetas, indexCvtorMap, fieldCvtorMap, params);
            out.flush();
        } catch (IOException e) {
            LOGGER.error("export file failed", e);
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    LOGGER.error("close file output stream failed", e);
                }
            }
        }
        return file;
    }

    protected abstract void doExport(OutputStream out, Collection<?> data, List<HeadMeta> headMetas,
        Map<Integer, IExportConvertor> indexCvtorMap, Map<String, IExportConvertor> fieldCvtorMap,
        Map<String, Object> params) throws IOException, ExportException;

    protected File genFile(String folderPath) {
        File file = null;
        do {
            file = new File(folderPath + File.separator + ExportConstant.FILE_NAME_PRE
                + String.valueOf(System.currentTimeMillis()) + this.getFileNameExt());
        } while (file.exists());
        file.getParentFile().mkdirs();
        return file;
    }

    protected Object obtainFieldVal(Object rowData, Map<Integer, IExportConvertor> indexCvtorMap,
        Map<String, IExportConvertor> fieldCvtorMap, String field, int rowIdx, int colIdx) {
        Object val = null;
        if (rowData != null) {
            if (rowData instanceof Model) {
                Model<?> model = (Model<?>)rowData;
                val = model.get(field);
            } else if (rowData instanceof Record) {
                Record record = (Record)rowData;
                val = record.get(field);
            } else if (rowData instanceof Map) {
                @SuppressWarnings("unchecked")
                Map<String, ?> map = (Map<String, ?>)rowData;
                val = map.get(field);
            } else {
                try {
                    val = PropertyUtils.getProperty(rowData, field);
                } catch (Exception e) {
                    AbstractExporter.LOGGER.error("failed to get property '" + field + "' from object", e);
                }
            }
        }
        IExportConvertor cvt = indexCvtorMap == null ? null : indexCvtorMap.get(Integer.valueOf(colIdx));
        if (fieldCvtorMap != null) {
            IExportConvertor fieldCvt = fieldCvtorMap.get(field);
            if (fieldCvt != null) {
                cvt = fieldCvt;
            }
        }
        if (cvt != null) {
            val = cvt.convertFieldVal(rowData, field, rowIdx, colIdx, val);
        }
        return val;
    }
}
